/*	ImageIO.c
 *
 *	Various Data Structures and Image loading routines.
 *
 *	Coded by Joseph A. Marrero
 *	http://www.ManVsCode.com/
 */

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cassert>	
#include "imageio.h"

namespace ImageIO {

void initialize( )
{
	#ifdef WIN32
	int i = _set_SSE2_enable( 1 );
	if( i ) fprintf( stdout, "SSE2 enabled.\n");
	else fprintf( stdout, "SSE2 not enabled; processor does not support SSE2.\n");
	#endif
}

void deinitialize( )
{
	#ifdef WIN32
	_set_SSE2_enable( 0 );
	#endif
}

Result loadImage( Image *img, const char *filename, ImageFileFormat format )
{
	Result result = FAILURE;
	#ifdef NDEBUG
	img->pixelData = NULL;
	#endif

	switch( format )
	{
		case BITMAP:
		{
			BitmapInfoHeader bmpInfoHeader;
			result = loadBitmapFile( filename, &bmpInfoHeader, &img->pixelData );
			assert( img->pixelData != NULL );
			img->bitsPerPixel = bmpInfoHeader.biBitCount;
			img->width = bmpInfoHeader.biWidth;
			img->height = bmpInfoHeader.biHeight;
			break;
		}
		case TARGA:
		{
			TargaFileHeader tgaHeader;
			result = loadTargaFile( filename, &tgaHeader, &img->pixelData );
			assert( img->pixelData != NULL );	
			img->bitsPerPixel = tgaHeader.bitCount;
			img->width = tgaHeader.width;
			img->height = tgaHeader.height;
			break;
		}
		default:
			break;
	}
	

	return result;
}

Result writeImage( Image *img, const char *filename, ImageFileFormat format )
{
	Result result = FAILURE;

	switch( format )
	{
		case BITMAP:
		{
			result = writeBitmapFile( filename, img->width, img->height, img->bitsPerPixel, img->pixelData );
			assert( img->pixelData != NULL );
			break;
		}
		case TARGA:
		{				
			TargaFileHeader tgaFileHeader;
			tgaFileHeader.bitCount = img->bitsPerPixel;
			tgaFileHeader.width = img->width;
			tgaFileHeader.height = img->height;
			result = writeTargaFile( filename, &tgaFileHeader, img->pixelData );
			break;
		}
		default:
			break;
	}
	

	return result;
}

void destroyImage( Image *img )
{
	delete [] img->pixelData;
	#ifdef NDEBUG
	img->pixelData = NULL;
	#endif
}

Result loadBitmapFile( const char *filename, BitmapInfoHeader *bitmapInfoHeader, byte **bitmap )
{
	FILE				*filePtr;
	BitmapFileHeader	BitmapFileHeader;
	register uint		imageIdx = 0;
	unsigned short bytesPerPixel = 0;
	uint bitmapSize = 0;
	uint scanlineBytes = 0;
	uint stride = 0;

	if( (filePtr = fopen( filename, "rb" )) == NULL )
	{
		*bitmap = NULL;
		return FAILURE;
	}

	//fread( &BitmapFileHeader, sizeof(BitmapFileHeader), 1, filePtr );
	fread( &BitmapFileHeader.bfType, sizeof(WORD), 1, filePtr );
	fread( &BitmapFileHeader.bfSize, sizeof(DWORD), 1, filePtr );
	fread( &BitmapFileHeader.bfReserved1, sizeof(WORD), 1, filePtr );
	fread( &BitmapFileHeader.bfReserved2, sizeof(WORD), 1, filePtr );
	fread( &BitmapFileHeader.bfOffBits, sizeof(DWORD), 1, filePtr );

	if( BitmapFileHeader.bfType != BITMAP_ID )
	{
		fclose(filePtr);
		*bitmap = NULL;
		return FAILURE;
	}

	fread( bitmapInfoHeader, sizeof(BitmapInfoHeader), 1, filePtr );	
	bytesPerPixel = bitmapInfoHeader->biBitCount >> 3;
	scanlineBytes = bitmapInfoHeader->biWidth * bytesPerPixel;
	stride = (bitmapInfoHeader->biWidth * bytesPerPixel + 3) & ~3;
	fseek( filePtr, BitmapFileHeader.bfOffBits, SEEK_SET );

	bitmapSize = scanlineBytes * bitmapInfoHeader->biHeight;	
	*bitmap = new byte[ bitmapSize ];

#ifdef NDEBUG
	memset( *bitmap, 0, bitmapSize );
#endif
	
	/* check if allocation failed... */
	if( *bitmap == NULL )
	{
		fclose( filePtr );
		return FAILURE;
	}

	for( imageIdx = 0; imageIdx < bitmapSize; imageIdx += scanlineBytes )
	{
		// read in pixels and skip padding...
		fread( *bitmap + imageIdx, scanlineBytes, 1, filePtr );		
		fseek( filePtr, stride - scanlineBytes, SEEK_CUR );
	}
	
	convertBGRtoRGB( bitmapInfoHeader->biWidth, bitmapInfoHeader->biHeight, bytesPerPixel, *bitmap );

	fclose( filePtr );
	return SUCCESS;
}

Result writeBitmapFile( const char *filename, uint width, uint height, uint bitsPerPixel, byte *imageData )
{
	FILE *filePtr;
	BitmapFileHeader BitmapFileHeader;
	BitmapInfoHeader bitmapInfoHeader;
	byte nullByte = NULL;
	uint imageIdx = 0;
	uint bitmapIdx = 0;
	uint bytesPerPixel = bitsPerPixel >> 3;
	uint stride = (width * bytesPerPixel + 3) & ~3;
	uint scanlineBytes = width * bytesPerPixel;

	if( (filePtr = fopen(filename, "wb")) == NULL )
		return FAILURE;

	/* Define the BitmapFileHeader */
	BitmapFileHeader.bfSize = sizeof(BitmapFileHeader);
	BitmapFileHeader.bfType = BITMAP_ID;
	BitmapFileHeader.bfReserved1 = 0;
	BitmapFileHeader.bfReserved2 = 0;
	BitmapFileHeader.bfOffBits = sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader);
	/* Define the BitmapInfoHeader */
	bitmapInfoHeader.biSize = sizeof(BitmapInfoHeader);
	bitmapInfoHeader.biPlanes = 1;
	bitmapInfoHeader.biBitCount = bitsPerPixel;	
	bitmapInfoHeader.biCompression = BI_RGB;		/* No compression */
	bitmapInfoHeader.biSizeImage = stride * height;  /* w * h * (4 bytes) */
	bitmapInfoHeader.biXPelsPerMeter = 0;
	bitmapInfoHeader.biYPelsPerMeter = 0;
	bitmapInfoHeader.biClrUsed = 0;
	bitmapInfoHeader.biClrImportant = 0;
	bitmapInfoHeader.biWidth = width;
	bitmapInfoHeader.biHeight = height;

	convertRGBtoBGR( width, height, bytesPerPixel, imageData );

	fwrite( &BitmapFileHeader, sizeof(BitmapFileHeader), 1, filePtr );
	fwrite( &bitmapInfoHeader, sizeof(BitmapInfoHeader), 1, filePtr );

	for( imageIdx = 0, bitmapIdx = 0; imageIdx <  bitmapInfoHeader.biSizeImage; imageIdx += stride, bitmapIdx += scanlineBytes )
	{
		fwrite( imageData + bitmapIdx, scanlineBytes, 1, filePtr );
		fwrite( &nullByte, 1, stride - scanlineBytes, filePtr );
	}

	fclose( filePtr );
	return SUCCESS;
}





Result loadTargaFile( const char *filename, TargaFileHeader *pTargaFileHeader, byte **bitmap )
{
	FILE *filePtr;
	uint colorMode;		/* 4 for RGBA or 3 for RGB */
	uint imageSize = 0;

	if( (filePtr = fopen( filename, "rb" )) == NULL )
		return FAILURE;

	/* read in first two bytes we don't need */
	fread( pTargaFileHeader, sizeof(TargaFileHeader), 1, filePtr );

	
	if( (pTargaFileHeader->imageTypeCode != 2) && (pTargaFileHeader->imageTypeCode != 3) )
	{
		fclose( filePtr );
		return FAILURE;
	}

	/* colorMode-> 3 = BGR, 4 = BGRA */
	colorMode = pTargaFileHeader->bitCount >> 3; // bytes per pixel
	

	imageSize = pTargaFileHeader->width * pTargaFileHeader->height * colorMode;

	*bitmap = new byte[ imageSize ];
	
	/* check if allocation failed... */
	if( *bitmap == NULL )
		return FAILURE;

	fread( *bitmap, 1, imageSize, filePtr );

	/* indexed color mode not handled!!! */
	convertBGRtoRGB( pTargaFileHeader->width, pTargaFileHeader->height, colorMode, *bitmap );

	fclose( filePtr );
	return SUCCESS;
}





Result writeTargaFile( const char *filename, TargaFileHeader *pTargaFileHeader, byte *bitmap )
{
	FILE *filePtr;
	long imageSize;		/* size of the Targa image */
	uint colorMode = pTargaFileHeader->bitCount >> 3; /* 4 for RGBA or 3 for RGB */


	if( ( filePtr = fopen( filename, "wb" ) ) == NULL )
		return FAILURE;

	pTargaFileHeader->imageIDLength     = 0;
	pTargaFileHeader->imageTypeCode     = 2;
	pTargaFileHeader->colorMapOrigin    = 0;
	pTargaFileHeader->colorMapLength    = 0;
	pTargaFileHeader->colorMapEntrySize = 0;
	pTargaFileHeader->colorMapType      = 0;
	pTargaFileHeader->imageXOrigin      = 0;
	pTargaFileHeader->imageYOrigin      = 0;
	pTargaFileHeader->imageDescriptor   = colorMode == 4 ? 0x08 : 0x00;

	assert( pTargaFileHeader->imageTypeCode == 0x2 || pTargaFileHeader->imageTypeCode == 0x3 ); // must be 2 or 3
	
	fwrite( pTargaFileHeader, sizeof(TargaFileHeader), 1, filePtr );
	
	convertRGBtoBGR( pTargaFileHeader->width, pTargaFileHeader->height, colorMode, bitmap );

	imageSize = pTargaFileHeader->width * pTargaFileHeader->height * colorMode;	
	fwrite( bitmap, imageSize, 1, filePtr );

	fclose( filePtr );
	return SUCCESS;
}

/*
 *  Image stretching functions...
 */
void resizeImage( uint srcWidth, uint srcHeight, const byte *srcBitmap,
				  uint dstWidth, uint dstHeight, byte *dstBitmap, uint bitsPerPixel,
				  ResizeAlgorithm algorithm )
{
	uint byteCount = bitsPerPixel >> 3;
	assert( srcBitmap != NULL || dstBitmap != NULL );
	assert( srcWidth != 0 || srcHeight != 0 );
	assert( byteCount > 2 );

	switch( algorithm )
	{
		case ALG_NEARESTNEIGHBOR:
			/* forces both bitmaps to have the same bit depth */
			fastResizeImage( srcWidth, srcHeight, bitsPerPixel, srcBitmap,
				             dstWidth, dstHeight, bitsPerPixel, dstBitmap );
			break;
		case ALG_BILINEAR:
			switch( byteCount )
			{
				case 0:
				case 1:
				case 2:
					assert( false ); /* unsupported bpp's */
					break;
				case 3:
						bilinearResizeImageRGB( srcWidth, srcHeight, srcBitmap, dstWidth, dstHeight, dstBitmap, byteCount );
						break;
				case 4:
						bilinearResizeImageRGBA( srcWidth, srcHeight, srcBitmap, dstWidth, dstHeight, dstBitmap, byteCount );
						break;
				default: break;
			}
			break;
		case ALG_BILINEAR_SHARPER:
			switch( byteCount )
			{
				case 0:
				case 1:
				case 2:
					assert( false ); /* unsupported bpp's */
					break;
				case 3:
						bilinearSharperResizeImageRGB( srcWidth, srcHeight, srcBitmap, dstWidth, dstHeight, dstBitmap, byteCount );
						break;
				case 4:
						bilinearSharperResizeImageRGBA( srcWidth, srcHeight, srcBitmap, dstWidth, dstHeight, dstBitmap, byteCount );
						break;
				default: break;
			}
			break;
		case ALG_BICUBIC: 
			switch( byteCount )
			{
				case 0:
				case 1:
				case 2:
					assert( false ); /* unsupported bpp's */
					break;
				case 3:
						bicubicResizeImageRGB( srcWidth, srcHeight, srcBitmap, dstWidth, dstHeight, dstBitmap, byteCount );
						break;
				case 4:
						bicubicResizeImageRGBA( srcWidth, srcHeight, srcBitmap, dstWidth, dstHeight, dstBitmap, byteCount );
						break;
				default: break;
			}
			break;
		default:
			assert( false ); /* bad algorithm... */
	}
}

/* uses nearest neighbor... */
void fastResizeImage( uint srcWidth, uint srcHeight, uint srcBitsPerPixel, const byte *srcBitmap,
					  uint dstWidth, uint dstHeight, uint dstBitsPerPixel, byte *dstBitmap ) /* uses nearest neighbor */
{
	uint srcByteCount = srcBitsPerPixel >> 3;
	uint dstByteCount = dstBitsPerPixel >> 3;
	register uint x = 0;
	register uint y = 0;
	float horizontalStretchFactor = 0;
	float verticalStretchFactor = 0;
	/* uint srcY, srcX;  /* don't remove */
	uint dstPos, srcPos;
	register uint srcYtimesWidth;
	register uint yTimesWidth;

	assert( srcBitsPerPixel != 0 || dstBitsPerPixel != 0 );
	assert( srcBitmap != NULL || dstBitmap != NULL );
	assert( srcWidth != 0 || srcHeight != 0 );
	horizontalStretchFactor = (float) srcWidth / (float) dstWidth;
	verticalStretchFactor = (float) srcHeight / (float) dstHeight;
	
	/* don't remove...
	 * x_in = x_out * (w_in / w_out), using nearest neighbor
	 */
	for( y = 0; y < dstHeight; y++ )
	{
		srcYtimesWidth = ((uint)(y * verticalStretchFactor)) * srcWidth * srcByteCount;
		yTimesWidth = y * dstWidth * dstByteCount;

		for( x = 0; x < dstWidth; x++ )
		{
			dstPos = yTimesWidth + x * dstByteCount;
			srcPos = srcYtimesWidth + ((uint)(x * horizontalStretchFactor)) * srcByteCount;		

			memcpy( &dstBitmap[ dstPos ], &srcBitmap[ srcPos ], dstByteCount * sizeof(byte) );
		}
	}

}



/* bi-linear: nearest neighbor with bilinear interpolation */
void bilinearResizeImageRGBA( uint srcWidth, uint srcHeight, const byte *srcBitmap,
				  uint dstWidth, uint dstHeight, byte *dstBitmap,
				  uint byteCount )
{
	register uint x = 0;
	register uint y = 0;
	float horizontalStretchFactor = 0;
	float verticalStretchFactor = 0;
	register uint srcY = 0;
	register uint srcX = 0;
	register uint dstPos,
		 neighborPos1,
		 neighborPos2,
		 neighborPos3,
		 neighborPos4;
	register byte n1R, n1G, n1B, n1A,	/* color vectors */
				  n2R, n2G, n2B, n2A,
				  n3R, n3G, n3B, n3A,
				  n4R, n4G, n4B, n4A;
	uint largestSrcIndex = srcWidth * srcHeight * byteCount;

	assert( byteCount == 4 );

	horizontalStretchFactor = (float) srcWidth / (float) dstWidth;  /* stretch vector */
	verticalStretchFactor = (float) srcHeight / (float) dstHeight;

	for( y = 0; y < dstHeight; y++ )
	{
		srcY = (uint) (y * verticalStretchFactor);
		if( srcY == 0 ) srcY = 1;

		for( x = 0; x < dstWidth; x++ )
		{
			srcX = (uint) (x * horizontalStretchFactor);
			dstPos = y * dstWidth * byteCount + x * byteCount;

			neighborPos1 = (srcY) * srcWidth * byteCount + (srcX) * byteCount;
			neighborPos2 = (srcY) * srcWidth * byteCount + (srcX+1) * byteCount;
			neighborPos3 = (srcY+1) * srcWidth * byteCount + (srcX) * byteCount;
			neighborPos4 = (srcY+1) * srcWidth * byteCount + (srcX+1) * byteCount;
			if( neighborPos1 >= largestSrcIndex ) neighborPos1 = largestSrcIndex - byteCount;
			if( neighborPos2 >= largestSrcIndex ) neighborPos2 = largestSrcIndex - byteCount;
			if( neighborPos3 >= largestSrcIndex ) neighborPos3 = largestSrcIndex - byteCount;
			if( neighborPos4 >= largestSrcIndex ) neighborPos4 = largestSrcIndex - byteCount;

			/* source pixel... */
			n1R = srcBitmap[ neighborPos1 ];
			n1G = srcBitmap[ neighborPos1 + 1 ];
			n1B = srcBitmap[ neighborPos1 + 2 ];
			n1A = srcBitmap[ neighborPos1 + 3 ];

			/* source pixel's neighbor2... */
			n2R = srcBitmap[ neighborPos2 ];
			n2G = srcBitmap[ neighborPos2 + 1 ];
			n2B = srcBitmap[ neighborPos2 + 2 ];
			n2A = srcBitmap[ neighborPos2 + 3 ];
				
			/* source pixel's neighbor3... */
			n3R = srcBitmap[ neighborPos3 ];
			n3G = srcBitmap[ neighborPos3 + 1 ];
			n3B = srcBitmap[ neighborPos3 + 2 ];
			n3A = srcBitmap[ neighborPos3 + 3 ];

			/* source pixel's neighbor4... */
			n4R = srcBitmap[ neighborPos4 ];
			n4G = srcBitmap[ neighborPos4 + 1 ];
			n4B = srcBitmap[ neighborPos4 + 2 ];
			n4A = srcBitmap[ neighborPos4 + 3 ];

			dstBitmap[ dstPos ] = (byte) bilerp( 0.5, 0.5, n4R, n3R, n2R, n1R );
			dstBitmap[ dstPos + 1 ] = (byte) bilerp( 0.5, 0.5, n4G, n3G, n2G, n1G );
			dstBitmap[ dstPos + 2 ] = (byte) bilerp( 0.5, 0.5, n4B, n3B, n2B, n1B );
			dstBitmap[ dstPos + 3 ] = (byte) bilerp( 0.5, 0.5, n4A, n3A, n2A, n1A );
		}
	}
}

void bilinearSharperResizeImageRGBA( uint srcWidth, uint srcHeight, const byte *srcBitmap,
									uint dstWidth, uint dstHeight, byte *dstBitmap,
									uint byteCount )
{
	register uint x = 0;
	register uint y = 0;
	float horizontalStretchFactor = 0;
	float verticalStretchFactor = 0;
	register uint srcY = 0;
	register uint srcX = 0;
	register uint dstPos, srcPos,
		 neighborPos1,
		 neighborPos2,
		 neighborPos3,
		 neighborPos4;
	register byte R, G, B, A,
			 n1R, n1G, n1B, n1A,	/* color vectors */
			 n2R, n2G, n2B, n2A,
			 n3R, n3G, n3B, n3A,
			 n4R, n4G, n4B, n4A;
	uint largestSrcIndex = srcWidth * srcHeight * byteCount;

	assert( byteCount == 4 );

	horizontalStretchFactor = (float) srcWidth / (float) dstWidth;  /* stretch vector */
	verticalStretchFactor = (float) srcHeight / (float) dstHeight;

	

	for( y = 0; y < dstHeight; y++ )
	{
		srcY = (uint) (y * verticalStretchFactor);
		if( srcY == 0 ) srcY = 1;

		for( x = 0; x < dstWidth; x++ )
		{
			srcX = (uint) (x * horizontalStretchFactor);
			dstPos = y * dstWidth * byteCount + x * byteCount;

			neighborPos1 = (srcY-1) * srcWidth * byteCount + (srcX-1) * byteCount;
			neighborPos2 = (srcY-1) * srcWidth * byteCount + (srcX+1) * byteCount;
			neighborPos3 = (srcY+1) * srcWidth * byteCount + (srcX-1) * byteCount;
			neighborPos4 = (srcY+1) * srcWidth * byteCount + (srcX+1) * byteCount;
			srcPos = (uint) srcY * srcWidth * byteCount + srcX * byteCount;

			if( neighborPos1 < 0 ) neighborPos1 = 0;
			if( neighborPos2 < 0 ) neighborPos2 = 0;
			if( neighborPos3 < 0 ) neighborPos3 = 0;
			if( neighborPos4 < 0 ) neighborPos4 = 0;
			if( neighborPos1 >= largestSrcIndex ) neighborPos1 = largestSrcIndex - byteCount;
			if( neighborPos2 >= largestSrcIndex ) neighborPos2 = largestSrcIndex - byteCount;
			if( neighborPos3 >= largestSrcIndex ) neighborPos3 = largestSrcIndex - byteCount;
			if( neighborPos4 >= largestSrcIndex ) neighborPos4 = largestSrcIndex - byteCount;

			/* source pixel... */
			R = srcBitmap[ srcPos ];
			G = srcBitmap[ srcPos + 1 ];
			B = srcBitmap[ srcPos + 2 ];
			A = srcBitmap[ srcPos + 3 ];

			/* source pixel's neighbor1... */
			n1R = srcBitmap[ neighborPos1 ];
			n1G = srcBitmap[ neighborPos1 + 1 ];
			n1B = srcBitmap[ neighborPos1 + 2 ];
			n1A = srcBitmap[ neighborPos1 + 3 ];

			/* source pixel's neighbor2... */
			n2R = srcBitmap[ neighborPos2 ];
			n2G = srcBitmap[ neighborPos2 + 1 ];
			n2B = srcBitmap[ neighborPos2 + 2 ];
			n2A = srcBitmap[ neighborPos2 + 3 ];
				
			/* source pixel's neighbor3... */
			n3R = srcBitmap[ neighborPos3 ];
			n3G = srcBitmap[ neighborPos3 + 1 ];
			n3B = srcBitmap[ neighborPos3 + 2 ];
			n3A = srcBitmap[ neighborPos3 + 3 ];

			/* source pixel's neighbor4... */
			n4R = srcBitmap[ neighborPos4 ];
			n4G = srcBitmap[ neighborPos4 + 1 ];
			n4B = srcBitmap[ neighborPos4 + 2 ];
			n4A = srcBitmap[ neighborPos4 + 3 ];

			/* comes out a little more burry than I expected, so I lerp between R and the 
			 * output from the bilerp of the other 4 samples.
			 */
			dstBitmap[ dstPos ] = (byte) lerp( 0.5, bilerp( 0.5, 0.5, n4R, n3R, n2R, n1R ), R );
			dstBitmap[ dstPos + 1 ] = (byte) lerp( 0.5, bilerp( 0.5, 0.5, n4G, n3G, n2G, n1G ), G );
			dstBitmap[ dstPos + 2 ] = (byte) lerp( 0.5, bilerp( 0.5, 0.5, n4B, n3B, n2B, n1B ), B );
			dstBitmap[ dstPos + 3 ] = (byte) lerp( 0.5, bilerp( 0.5, 0.5, n4A, n3A, n2A, n1A ), A );
		}
	}
}

void bilinearResizeImageRGB( uint srcWidth, uint srcHeight, const byte *srcBitmap,
				  uint dstWidth, uint dstHeight, byte *dstBitmap,
				  uint byteCount )
{
	register uint x = 0;
	register uint y = 0;
	float horizontalStretchFactor = 0;
	float verticalStretchFactor = 0;
	register uint srcY = 0;
	register uint srcX = 0;
	register uint dstPos, 
                  neighborPos1,
                  neighborPos2,
                  neighborPos3,
                  neighborPos4;
	register byte n1R, n1G, n1B, 	/* color vectors */
                  n2R, n2G, n2B, 
                  n3R, n3G, n3B, 
                  n4R, n4G, n4B;

	assert( byteCount == 3 );

	horizontalStretchFactor = (float) srcWidth / (float) dstWidth;  /* stretch vector */
	verticalStretchFactor = (float) srcHeight / (float) dstHeight;

	
	for( y = 0; y < dstHeight; y++ )
	{
		srcY = (uint) (y * verticalStretchFactor);
		assert( srcY < srcHeight );

		for( x = 0; x < dstWidth; x++ )
		{
			srcX = (uint) (x * horizontalStretchFactor);
			dstPos = y * dstWidth * byteCount + x * byteCount;

			neighborPos1 = (srcY) * srcWidth * byteCount + (srcX) * byteCount;
			neighborPos2 = (srcY) * srcWidth * byteCount + (srcX+1) * byteCount;
			neighborPos3 = (srcY+1) * srcWidth * byteCount + (srcX) * byteCount;
			neighborPos4 = (srcY+1) * srcWidth * byteCount + (srcX+1) * byteCount;

			/* source pixel... */
			n1R = srcBitmap[ neighborPos1 ];
			n1G = srcBitmap[ neighborPos1 + 1 ];
			n1B = srcBitmap[ neighborPos1 + 2 ];

			/* source pixel's neighbor2... */
			n2R = srcBitmap[ neighborPos2 ];
			n2G = srcBitmap[ neighborPos2 + 1 ];
			n2B = srcBitmap[ neighborPos2 + 2 ];
				
			/* source pixel's neighbor3... */
			n3R = srcBitmap[ neighborPos3 ];
			n3G = srcBitmap[ neighborPos3 + 1 ];
			n3B = srcBitmap[ neighborPos3 + 2 ];

			/* source pixel's neighbor4... */
			n4R = srcBitmap[ neighborPos4 ];
			n4G = srcBitmap[ neighborPos4 + 1 ];
			n4B = srcBitmap[ neighborPos4 + 2 ];

			dstBitmap[ dstPos ]     = (byte) bilerp( 0.5, 0.5, n4R, n3R, n2R, n1R );
			dstBitmap[ dstPos + 1 ] = (byte) bilerp( 0.5, 0.5, n4G, n3G, n2G, n1G );
			dstBitmap[ dstPos + 2 ] = (byte) bilerp( 0.5, 0.5, n4B, n3B, n2B, n1B );
		}
	}
}


void bilinearSharperResizeImageRGB( uint srcWidth, uint srcHeight, const byte *srcBitmap,
								   uint dstWidth, uint dstHeight, byte *dstBitmap,
								   uint byteCount )
{
	register uint x = 0;
	register uint y = 0;
	float horizontalStretchFactor = 0;
	float verticalStretchFactor = 0;
	register uint srcY = 0;
	register uint srcX = 0;
	register uint dstPos, srcPos,
		 neighborPos1,
		 neighborPos2,
		 neighborPos3,
		 neighborPos4;
	register byte R, G, B,
			 n1R, n1G, n1B, 	/* color vectors */
			 n2R, n2G, n2B, 
			 n3R, n3G, n3B, 
			 n4R, n4G, n4B;
	uint largestSrcIndex = srcWidth * srcHeight * byteCount;

	assert( byteCount == 3 );

	horizontalStretchFactor = (float) srcWidth / (float) dstWidth;  /* stretch vector */
	verticalStretchFactor   = (float) srcHeight / (float) dstHeight;
	
	for( y = 0; y < dstHeight; y++ )
	{
		srcY = (uint) (y * verticalStretchFactor);
		assert( srcY < srcHeight );

		for( x = 0; x < dstWidth; x++ )
		{
			srcX = (uint) (x * horizontalStretchFactor);
			dstPos = y * dstWidth * byteCount + x * byteCount;

			neighborPos1 = (srcY-1) * srcWidth * byteCount + (srcX-1) * byteCount;
			neighborPos2 = (srcY-1) * srcWidth * byteCount + (srcX+1) * byteCount;
			neighborPos3 = (srcY+1) * srcWidth * byteCount + (srcX-1) * byteCount;
			neighborPos4 = (srcY+1) * srcWidth * byteCount + (srcX+1) * byteCount;
			srcPos = (uint) srcY * srcWidth * byteCount + srcX * byteCount;

			if( neighborPos1 < 0 ) neighborPos1 = 0;
			if( neighborPos2 < 0 ) neighborPos2 = 0;
			if( neighborPos3 < 0 ) neighborPos3 = 0;
			if( neighborPos4 < 0 ) neighborPos4 = 0;
			if( neighborPos1 >= largestSrcIndex ) neighborPos1 = largestSrcIndex - byteCount;
			if( neighborPos2 >= largestSrcIndex ) neighborPos2 = largestSrcIndex - byteCount;
			if( neighborPos3 >= largestSrcIndex ) neighborPos3 = largestSrcIndex - byteCount;
			if( neighborPos4 >= largestSrcIndex ) neighborPos4 = largestSrcIndex - byteCount;

			/* source pixel... */
			R = srcBitmap[ srcPos ];
			G = srcBitmap[ srcPos + 1 ];
			B = srcBitmap[ srcPos + 2 ];

			/* source pixel's neighbor1... */
			n1R = srcBitmap[ neighborPos1 ];
			n1G = srcBitmap[ neighborPos1 + 1 ];
			n1B = srcBitmap[ neighborPos1 + 2 ];

			/* source pixel's neighbor2... */
			n2R = srcBitmap[ neighborPos2 ];
			n2G = srcBitmap[ neighborPos2 + 1 ];
			n2B = srcBitmap[ neighborPos2 + 2 ];
				
			/* source pixel's neighbor3... */
			n3R = srcBitmap[ neighborPos3 ];
			n3G = srcBitmap[ neighborPos3 + 1 ];
			n3B = srcBitmap[ neighborPos3 + 2 ];

			/* source pixel's neighbor4... */
			n4R = srcBitmap[ neighborPos4 ];
			n4G = srcBitmap[ neighborPos4 + 1 ];
			n4B = srcBitmap[ neighborPos4 + 2 ];

			/* comes out a little more burry than I expected, so I lerp between R and the 
			 * output from the bilerp of the other 4 samples.
			 */
			dstBitmap[ dstPos ]     = (byte) lerp( 0.5, bilerp( 0.5, 0.5, n4R, n3R, n2R, n1R ), R );
			dstBitmap[ dstPos + 1 ] = (byte) lerp( 0.5, bilerp( 0.5, 0.5, n4G, n3G, n2G, n1G ), G );
			dstBitmap[ dstPos + 2 ] = (byte) lerp( 0.5, bilerp( 0.5, 0.5, n4B, n3B, n2B, n1B ), B );
		}
	}
}
 /* uses a cubic B-Spline */
void bicubicResizeImageRGBA( uint srcWidth, uint srcHeight, const byte *srcBitmap,
							 uint dstWidth, uint dstHeight, byte *dstBitmap,
							 uint byteCount )
{
	register uint x = 0;
	register uint y = 0;
	register int m = 0, n = 0, i = 0, j = 0;
	float horizontalStretchFactor = 0;
	float verticalStretchFactor = 0;
	register float srcY = 0;
	register float srcX = 0;
	register float dy = 0;
	register float dx = 0;
	register uint dstPos, srcPos;
	uint largestSrcIndex = srcWidth * srcHeight * byteCount;
	register uint sumR = 0;
	register uint sumG = 0;
	register uint sumB = 0;
	register uint sumA = 0;

	assert( byteCount == 4 );

	horizontalStretchFactor = (float) srcWidth / (float) dstWidth;  /* stretch vector */
	verticalStretchFactor = (float) srcHeight / (float) dstHeight;

	

	for( y = 0; y < dstHeight; y++ )
	{
		srcY = y * verticalStretchFactor;
		j = (int) floor( srcY );
		if( srcY == 0 ) srcY = 1;
		

		for( x = 0; x < dstWidth; x++ )
		{
			srcX = x * horizontalStretchFactor;
			i = (int) floor( srcX );
			
			dstPos = y * dstWidth * byteCount + x * byteCount;
			sumR = 0;
			sumG = 0;
			sumB = 0;
			sumA = 0;
			dy = srcY - j;
			dx = srcX - i;
			
			for( m = -1; m <= 2; m++ )
				for( n = -1; n <= 2; n++ )
				{
					srcPos = iPosition( i + m, j + n, byteCount, srcWidth );
					if( srcPos > largestSrcIndex ) srcPos = largestSrcIndex - byteCount;

					sumR +=	(uint) srcBitmap[ srcPos ] * R( m - dx ) * R( dy - n );
					sumG +=	(uint) srcBitmap[ srcPos + 1 ] * R( m - dx ) * R( dy - n );
					sumB +=	(uint) srcBitmap[ srcPos + 2 ] * R( m - dx ) * R( dy - n );
					sumA +=	(uint) srcBitmap[ srcPos + 3 ] * R( m - dx ) * R( dy - n );
				}

			dstBitmap[ dstPos ]     = (byte) sumR;
			dstBitmap[ dstPos + 1 ] = (byte) sumG;
			dstBitmap[ dstPos + 2 ] = (byte) sumB;
			dstBitmap[ dstPos + 3 ] = (byte) sumA;
		}
	}
}

void bicubicResizeImageRGB( uint srcWidth, uint srcHeight, const byte *srcBitmap,
							uint dstWidth, uint dstHeight, byte *dstBitmap,
							uint byteCount )
{
	register uint x = 0;
	register uint y = 0;
	register int m = 0, n = 0, i = 0, j = 0;
	float horizontalStretchFactor = 0;
	float verticalStretchFactor = 0;
	register float srcY = 0;
	register float srcX = 0;
	register float dy = 0;
	register float dx = 0;
	register uint dstPos, srcPos;
	uint largestSrcIndex = srcWidth * srcHeight * byteCount;
	register uint sumR = 0;
	register uint sumG = 0;
	register uint sumB = 0;
	assert( byteCount == 4 );

	horizontalStretchFactor = (float) srcWidth / (float) dstWidth;  /* stretch vector */
	verticalStretchFactor = (float) srcHeight / (float) dstHeight;

	

	for( y = 0; y < dstHeight; y++ )
	{
		srcY = y * verticalStretchFactor;
		j = (int) floor( srcY );
		if( srcY == 0 ) srcY = 1;
		

		for( x = 0; x < dstWidth - 2; x++ )
		{
			srcX = x * horizontalStretchFactor;
			i    = (int) floor( srcX );
			
			dstPos = y * dstWidth * byteCount + x * byteCount;
			sumR   = 0;
			sumG   = 0;
			sumB   = 0;
			dy     = srcY - j;
			dx     = srcX - i;
			
			for( m = -1; m <= 2; m++ )
				for( n = -1; n <= 2; n++ )
				{
					srcPos = iPosition( i + m, j + n, byteCount, srcWidth );
					if( srcPos > largestSrcIndex ) srcPos = largestSrcIndex - byteCount;

					sumR +=	(uint) srcBitmap[ srcPos ] * R( m - dx ) * R( dy - n );
					sumG +=	(uint) srcBitmap[ srcPos + 1 ] * R( m - dx ) * R( dy - n );
					sumB +=	(uint) srcBitmap[ srcPos + 2 ] * R( m - dx ) * R( dy - n );
				}

			dstBitmap[ dstPos ]     = (byte) sumR;
			dstBitmap[ dstPos + 1 ] = (byte) sumG;
			dstBitmap[ dstPos + 2 ] = (byte) sumB;
		}
	}
}

/*
 *	Swap Red and blue colors in RGB abd RGBA functions
 */
void swapRBinRGB( uint width, uint height, uint byteCount, byte *bitmap ) /* RGB to BGR */
{
	register uint imageIdx;
	register uint imageSize = width * height * byteCount;
	assert( byteCount != 0 );
	assert( bitmap != NULL );

	if( byteCount > 2 ) /* 32 bpp or 24 bpp */
	{	
		for( imageIdx = 0; imageIdx < imageSize; imageIdx += byteCount )
		{
			/* fast swap using XOR... */
			bitmap[ imageIdx ]     = bitmap[ imageIdx ] ^ bitmap[ imageIdx + 2 ];
			bitmap[ imageIdx + 2 ] = bitmap[ imageIdx + 2 ] ^ bitmap[ imageIdx ];
			bitmap[ imageIdx ]     = bitmap[ imageIdx ] ^ bitmap[ imageIdx + 2 ]; 
		}
	}
	else { /* 16 bpp */
		/* Swap ARRRRRGGGGGBBBBB to GGGBBBBBARRRRRGG, whereeach R,G,B, A is a bit, or... */
		/* Swap GGGBBBBBARRRRRGG to ARRRRRGGGGGBBBBB, whereeach R,G,B, A is a bit */
		for( imageIdx = 0; imageIdx < imageSize; imageIdx += byteCount )
		{			
			bitmap[ imageIdx ]     = bitmap[ imageIdx + 1 ];
			bitmap[ imageIdx + 1 ] = bitmap[ imageIdx ];
		}
	}

}

/*
 *  Image Flipping Routines. These are slow... :(
 */
void flipImageHorizontally( uint width, uint height, uint byteCount, byte *bitmap )
{
	register uint x = 0;
	register uint y = 0;
	byte *srcBitmap = new byte[ sizeof(byte) * width * height * byteCount ];

	memcpy( srcBitmap, bitmap, sizeof(byte) * width * height * byteCount );
	
	for( y = 0; y < height; y++ )
		for( x = 0; x < width; x++ )
			memcpy( &bitmap[ iPosition(width - x - 1, y, byteCount, width) ], &srcBitmap[ iPosition(x, y, byteCount, width) ], sizeof(byte) * byteCount );

	delete [] srcBitmap;
}

void flipImageVertically( uint width, uint height, uint byteCount, byte *bitmap )
{
	register uint x = 0;
	register uint y = 0;
	byte *srcBitmap = new byte[ sizeof(byte) * width * height * byteCount ];

	memcpy( srcBitmap, bitmap, sizeof(byte) * width * height * byteCount );
	
	for( y = 0; y < height; y++ )
		for( x = 0; x < width; x++ )
			memcpy( &bitmap[ iPosition(x, height - y - 1, byteCount, width) ], &srcBitmap[ iPosition(x, y, byteCount, width) ], sizeof(byte) * byteCount );

	delete [] srcBitmap;
}
/*
 *	Flip image vertically/horizontally without a copy...
 */
void flipXImage( uint width, uint height, const byte *srcBitmap, byte *dstBitmap, uint byteCount )
{
	register uint j, i;
	register uint j_times_width = 0;
	register uint b = 0;
	register byte *temp = new byte[ width * byteCount * sizeof(byte) ]; /* temp scan line, just in case src = dst */

	for( j = 0; j < height; j++ )
	{
		j_times_width = j* width * byteCount; /* avoids doing this twice */
		
		memcpy( &temp[ 0 ], &srcBitmap[ j_times_width ], width * byteCount * sizeof(byte) );

		for( i = 0; i < width; i++ )
			memcpy( &dstBitmap[ j_times_width + (width - 1 - i) * byteCount ], &temp[ i * byteCount ], byteCount * sizeof(byte) );
	}

	delete [] temp;
}

void flipYImage( uint width, uint height, const byte *srcBitmap, byte *dstBitmap, uint byteCount )
{
	register uint j, i;
	register uint i_times_bytecount = 0;
	register uint width_times_bytecount = 0;
	register uint b = 0;
	register byte *temp = new byte[ height * byteCount * sizeof(byte) ]; /* temp column line, just in case src = dst */

	for( i = 0; i < width; i++ )
	{
		i_times_bytecount = i * byteCount;
		width_times_bytecount = width * byteCount;

		for( j = 0; j < height; j++ )
			memcpy( &temp[ j * byteCount ], &srcBitmap[ j * width_times_bytecount + i_times_bytecount ], byteCount * sizeof(byte) );

		for( j = 0; j < height; j++ )
			memcpy( &dstBitmap[ (height - 1 - j) * width_times_bytecount + i_times_bytecount ], &temp[ j * byteCount ], byteCount * sizeof(byte) );
	}

	delete [] temp;
}

void convertRGBtoBGR( uint width, uint height, uint byteCount, byte *bitmap )
{ swapRBinRGB( width, height, byteCount, bitmap ); }
void convertBGRtoRGB( uint width, uint height, uint byteCount, byte *bitmap )
{ swapRBinRGB( width, height, byteCount, bitmap ); }



#ifndef _NO_IMAGE_PROCESSING
/*
 * Edge Detection: k is the maximum color distance that signifies an edge
 */
void detectEdges( uint width, uint height, uint bitsPerPixel, const byte *srcBitmap, byte *dstBitmap, uint k )
{
	uint byteCount = bitsPerPixel >> 3; /* 4 ==> RGBA32, 3==>RGB32 , 2 ==> RGB16 */
	register uint y;
	register uint x;
	assert( bitsPerPixel != 0 );
	assert( srcBitmap != NULL || dstBitmap != NULL );

	for( y = 0; y < height - 1; y++ )
		for( x = 0; x < width - 1; x++ )
		{
			/* r = right, b = bottom */
			uint pos = width * y * byteCount + x * byteCount;
			uint rpos = width * y * byteCount + (x + 1) * byteCount;
			uint bpos = width * (y + 1) * byteCount + x * byteCount;

			/* this pixel */
			byte R = srcBitmap[ pos ];
			byte G = srcBitmap[ pos + 1 ];
			byte B = srcBitmap[ pos + 2 ];

			/* right neighbor */
			byte rR = srcBitmap[ rpos ];
			byte rG = srcBitmap[ rpos + 1 ];
			byte rB = srcBitmap[ rpos + 2 ];

			/* bottom neighbor */
			byte bR = srcBitmap[ bpos ];
			byte bG = srcBitmap[ bpos + 1 ];
			byte bB = srcBitmap[ bpos + 2 ];
			
			/*
			uint D1 = sqrt( (R-rR)*(R-rR) + (G-rG)*(G-rG) + (B-rB)*(B-rB) );
			uint D2 = sqrt( (R-bR)*(R-bR) + (G-bG)*(G-bG) + (B-bB)*(B-bB) );
			*/
			
			/* if any of the distances are greater than k, put a white pixel in the destination */
			if( (R-rR)*(R-rR) + (G-rG)*(G-rG) + (B-rB)*(B-rB) >= k*k ||
				(R-bR)*(R-bR) + (G-bG)*(G-bG) + (B-bB)*(B-bB) >= k*k ) /* if( D1 > k || D2 > k ) */
			{
				dstBitmap[ pos ] = 0xFF;
				dstBitmap[ pos + 1 ] = 0xFF;
				dstBitmap[ pos + 2 ] = 0xFF;
			}
			else { /* otherwise place a black pixel; */
				dstBitmap[ pos ] = 0x00;
				dstBitmap[ pos + 1 ] = 0x00;
				dstBitmap[ pos + 2 ] = 0x00;			
			}

		}
}

/*
 * Color Extraction: Marks white all the pixels that are no greater than k distance to the color.
 */
void extractColor( uint width, uint height, uint bitsPerPixel, const byte *srcBitmap, byte *dstBitmap, const RGB *color, uint k )
{
	uint byteCount = bitsPerPixel >> 3; /* 4 ==> RGBA32, 3==>RGB32 , 2 ==> RGB16 */
	register uint y;
	register uint x;
	assert( bitsPerPixel != 0 );
	assert( srcBitmap != NULL || dstBitmap != NULL );

	for( y = 0; y < height; y++ )
		for( x = 0; x < width; x++ )
		{
			uint pos = width * y * byteCount + x * byteCount;
			/* this pixel */
			byte R = srcBitmap[ pos ];
			byte G = srcBitmap[ pos + 1 ];
			byte B = srcBitmap[ pos + 2 ];

			if( (R-color->r)*(R-color->r) + (G-color->g)*(G-color->g) + (B-color->b)*(B-color->b) <= k*k ) /*if( sqrt( (R-color->r) + (G-color->g) + (B-color->b) ) <= k )*/
			{
				dstBitmap[ pos ] = 0xFF;
				dstBitmap[ pos + 1 ] = 0xFF;
				dstBitmap[ pos + 2 ] = 0xFF;
			}
			else {
				dstBitmap[ pos ] = 0x00;
				dstBitmap[ pos + 1 ] = 0x00;
				dstBitmap[ pos + 2 ] = 0x00;
			}
		}
}

/*
 * Grayscale conversion
 */
void convertToGrayscale( uint width, uint height, uint bitsPerPixel, const byte *srcBitmap, byte *dstBitmap )
{
	uint byteCount = bitsPerPixel >> 3; /* 4 ==> RGBA32, 3==>RGB32 , 2 ==> RGB16 */
	register uint y;
	register uint x;
	assert( bitsPerPixel != 0 );
	assert( srcBitmap != NULL || dstBitmap != NULL );

	for( y = 0; y < height; y++ )
		for( x = 0; x < width; x++ )
		{
			uint pos = width * y * byteCount + x * byteCount;
			/* this pixel */
			byte R = srcBitmap[ pos ];
			byte G = srcBitmap[ pos + 1 ];
			byte B = srcBitmap[ pos + 2 ];

			uint colorAverage = (R + G + B) / 3;
			
			dstBitmap[ pos ] = colorAverage;
			dstBitmap[ pos + 1 ] = colorAverage;
			dstBitmap[ pos + 2 ] = colorAverage;
		}
}

/*
 * Colorscale conversion
 */
void convertToColorscale( uint width, uint height, uint bitsPerPixel, const byte *srcBitmap, byte *dstBitmap, const RGB *color )
{
	uint byteCount = bitsPerPixel >> 3; /* 4 ==> RGBA32, 3==>RGB32 , 2 ==> RGB16 */
	register uint y;
	register uint x;
	assert( (color->r != 0 && color->g != 0 && color->b != 0) ||
			(color->r != 0 || color->g != 0 || color->b != 0) ); /* no black, because 0 vector */
	assert( srcBitmap != NULL || dstBitmap != NULL );
	assert( bitsPerPixel != 0 );

	for( y = 0; y < height; y++ )
		for( x = 0; x < width; x++ )
		{
			uint pos = width * y * byteCount + x * byteCount;
			/* this pixel */
			byte R = srcBitmap[ pos ];
			byte G = srcBitmap[ pos + 1 ];
			byte B = srcBitmap[ pos + 2 ];

			/*float a = sqrt(R*R + G*G + B*B);
			float b = sqrt((float)color->r*color->r + (float)color->g*color->g + (float)color->b*color->b);
			float colorScaled = (R*color->r + G*color->g + B*color->b) / ( a * b );*/
			
			float colorScaled = (float) ( (R*color->r + G*color->g + B*color->b) / ( sqrt((float) R*R + G*G + B*B) * sqrt((float) color->r*color->r + color->g*color->g + color->b*color->b) ));
			
			dstBitmap[ pos ] = (byte) colorScaled * R;
			dstBitmap[ pos + 1 ] = (byte) colorScaled * G;
			dstBitmap[ pos + 2 ] = (byte) colorScaled * B;
		}
}

/*
 * Light or contrast modification
 */
void modifyContrast( uint width, uint height, uint bitsPerPixel, const byte *srcBitmap, byte *dstBitmap, int contrast )
{
	uint byteCount = bitsPerPixel >> 3; /* 4 ==> RGBA32, 3==>RGB32 , 2 ==> RGB16 */
	register uint y;
	register uint x;
	register uint colorIndex;
	uint transform[ 256 ];
	assert( srcBitmap != NULL || dstBitmap != NULL );
	assert( bitsPerPixel != 0 );

	for( colorIndex = 0; colorIndex < 256; colorIndex++ )
	{
		float slope = (float) tan((float)contrast);
		if( colorIndex < (uint) (128.0f + 128.0f*slope) && colorIndex > (uint) (128.0f-128.0f*slope) )
			transform[ colorIndex ] = (uint) ((colorIndex - 128) / slope + 128);
		else if( colorIndex >= (uint) (128.0f + 128.0f*slope) )
			transform[ colorIndex ] = 255;
		else /* colorIndex <= 128 -128*slope */
			transform[ colorIndex ] = 0;
	}

	
	for( y = 0; y < height; y++ )
		for( x = 0; x < width; x++ )
		{
			uint pos = width * y * byteCount + x * byteCount;
			/* this pixel */
			byte R = srcBitmap[ pos ];
			byte G = srcBitmap[ pos + 1 ];
			byte B = srcBitmap[ pos + 2 ];

			dstBitmap[ pos ] = transform[ R ];
			dstBitmap[ pos + 1 ] = transform[ G ];
			dstBitmap[ pos + 2 ] = transform[ B ];
		}
}

void modifyBrightness( uint width, uint height, uint bitsPerPixel, const byte *srcBitmap, byte *dstBitmap, int brightness )
{
	uint byteCount = bitsPerPixel >> 3; /* 4 ==> RGBA32, 3==>RGB32 , 2 ==> RGB16 */
	register uint y;
	register uint x;
	register unsigned short colorIndex;
	byte transform[ 256 ] = {0};
	assert( srcBitmap != NULL || dstBitmap != NULL );
	assert( bitsPerPixel != 0 );

	for( colorIndex = 0; colorIndex < 256; colorIndex++ )
	{
		short t = colorIndex + brightness;
		if( t > 255 ) t = 255;
		if( t < 0 )	t = 0;		
		transform[ colorIndex ] = (byte) t;
	}

	
	for( y = 0; y < height; y++ )
	{
		for( x = 0; x < width; x++ )
		{
			uint pos = width * y * byteCount + x * byteCount;
			/* this pixel */
			byte R = srcBitmap[ pos ];
			byte G = srcBitmap[ pos + 1 ];
			byte B = srcBitmap[ pos + 2 ];

			dstBitmap[ pos ] = transform[ R ];
			dstBitmap[ pos + 1 ] = transform[ G ];
			dstBitmap[ pos + 2 ] = transform[ B ];
		}
	}
}
#endif

#ifdef __cplusplus
} // end of ImageIO namespace
#endif
